#if UNITY_EDITOR

using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

// 这里要用脚本并且运行时分析性能的原因是为了获得正确的UnityStats.batches数据
// ReSharper disable once CheckNamespace

public class SfxProfilerRunner : MonoBehaviour
{
    public ISfxProfiler m_Profiler;
    
    [Serializable]
    public class ProfileInput
    {
        public GameObject m_Prefab;
        public string m_GPUArchitecture;
    }
    
    [Serializable]
    public class AwakeCallbackInfo
    {
        public string m_AssemblyName;
        public string m_ClassName;
        public string m_FunctionName;
        public bool m_IsPublic;
    }

    private static AwakeCallbackInfo m_DefaultAwakeCallbackInfo = new AwakeCallbackInfo()
    {
        m_AssemblyName = "Assembly-CSharp-Editor",
        m_ClassName = "SfxProfiler",
        m_FunctionName = "OnEnterPlayMode",
        m_IsPublic = false
    };

    public List<ProfileInput> m_ProfileInputs = new List<ProfileInput>();
    public List<AwakeCallbackInfo> m_AwakeCallbackInfos = new List<AwakeCallbackInfo>();
    public List<GameObject> m_EffectInsts = new List<GameObject>();
    public List<float> m_EffectDurations = new List<float>();
    [NonSerialized] public int m_LastIndex = -1;
    [NonSerialized] public int m_CurIndex = 0;
    
    public Func<GameObject, string, float, float, bool> m_OnUpdateProfile;
    public Action<GameObject, string> m_UpdateToStartProfile;
    
    public Action m_OnEndProfile;
    
    private float m_PlayProgress;

    public void Awake()
    {
        m_LastIndex = -1;
        m_CurIndex = 0;
        AppDomain domain = AppDomain.CurrentDomain;
        Assembly[] assemblies = domain.GetAssemblies();

        if (!m_AwakeCallbackInfos.Contains(m_DefaultAwakeCallbackInfo))
        {
            m_AwakeCallbackInfos.Add(m_DefaultAwakeCallbackInfo);
        }

        for (int i = 0; i < m_AwakeCallbackInfos.Count; ++i)
        {
            AwakeCallbackInfo callbackInfo = m_AwakeCallbackInfos[i];
            
            Assembly editorAssembly = null;
            foreach (Assembly assembly in assemblies)
            {
                if (assembly.FullName.StartsWith(callbackInfo.m_AssemblyName + ","))
                {
                    editorAssembly = assembly;
                    break;
                }
            }
            if (editorAssembly == null)
            {
                continue;
            }
            Type type = editorAssembly.GetType(callbackInfo.m_ClassName);
            if (type == null)
            {
                continue;
            }
            BindingFlags flags = callbackInfo.m_IsPublic
                ? BindingFlags.Static | BindingFlags.Public
                : BindingFlags.Static | BindingFlags.NonPublic;
            MethodInfo methodInfo = type.GetMethod(callbackInfo.m_FunctionName, flags);
            if (methodInfo != null)
            {
                methodInfo.Invoke(null, null);
            }
        }
        
        m_Profiler.SetEndProfileCallbakc(m_OnEndProfile);
    }

    private void OnApplicationQuit()
    {
        if (m_Profiler != null)
        {
            m_Profiler.OnEndProfile(m_EffectInsts.Count);
        }
    }

    private void LateUpdate()
    {
        if (m_Profiler == null)
        {
            return;
        }
        if (m_CurIndex != m_LastIndex)
        {
            m_PlayProgress = 0.0f;
            m_Profiler.OnStartProfile(m_EffectInsts[m_CurIndex], m_EffectDurations[m_CurIndex], m_CurIndex);
            m_LastIndex = m_CurIndex;
        }
        if (m_UpdateToStartProfile != null)
        {
            ProfileInput input = m_ProfileInputs[m_CurIndex];
            m_UpdateToStartProfile(m_EffectInsts[m_CurIndex], input.m_GPUArchitecture);
        }
        if (m_OnUpdateProfile != null)
        {
            m_PlayProgress += Time.deltaTime;
            ProfileInput input = m_ProfileInputs[m_CurIndex];
            if (m_OnUpdateProfile(m_EffectInsts[m_CurIndex], input.m_GPUArchitecture, m_PlayProgress, m_EffectDurations[m_CurIndex]))
            {
                m_Profiler.OnEndProfile(m_CurIndex);
                m_PlayProgress = 0.0f;
                ++m_CurIndex;
                if (m_CurIndex >= m_EffectInsts.Count)
                {
                    m_Profiler = null;
                }
            }
        }
    }
}

public interface ISfxProfiler
{
    public void SetEndProfileCallbakc(Action callback);
    public void OnStartProfile(GameObject effectInst, float duration, int index);
    public void OnEndProfile(int index);
}
    
#endif